#include "SCheckComboBox.h"

#include <core/ImageMgr.h>
#include <core/StyleMgr.h>

#include <QCheckBox>
#include <QEvent>
#include <QLineEdit>
#include <QPainter>

SCheckComboBox::SCheckComboBox(QWidget* parent, bool hasCheckAll /* = false*/,
                               const QString& checkAllText /* = ""*/)
    : QComboBox(parent),
      m_hasCheckAll(hasCheckAll),
      m_checkBoxAll(nullptr),
      m_listWidget(new QListWidget(this)),
      m_lineEdit(new QLineEdit(this)) {
  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  QWidget* container = static_cast<QWidget*>(view()->parent());
  container->setAttribute(Qt::WA_TranslucentBackground);
  container->setWindowFlag(Qt::FramelessWindowHint);
  container->setWindowFlag(Qt::NoDropShadowWindowHint);
  container->setContentsMargins(0, 0, 0, 0);

  setStyleSheet(styleSheet());
  setModel(m_listWidget->model());
  setView(m_listWidget);
  setLineEdit(m_lineEdit);

  if (m_hasCheckAll) {
    QListWidgetItem* listWidgetItem = new QListWidgetItem(m_listWidget);
    m_checkBoxAll = new QCheckBox(this);
    m_checkBoxAll->setTristate(true);
    m_checkBoxAll->setText(checkAllText);
    m_listWidget->addItem(listWidgetItem);
    m_listWidget->setItemWidget(listWidgetItem, m_checkBoxAll);
    connect(m_checkBoxAll, &QCheckBox::clicked, this,
            &SCheckComboBox::onCheckBoxClicked);
  }

  m_lineEdit->setReadOnly(true);
  m_lineEdit->installEventFilter(this);
  connect(this, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
          this, &SCheckComboBox::itemClicked);
}

QString SCheckComboBox::styleSheet() const {
  return QString(
             "QComboBox						            "
             "{color:#%1; padding: 4px 5px 4px 8px; "
             "border-radius:2px;border:1px solid #%3; background-color:#%2;}"
             "QComboBox:hover				            "
             "{background-color:#%2;}"
             "QComboBox:on					            "
             "{color:#%4;border:1px solid "
             "#%4;background-color:#%2;border-radius:2px;}"
             "QComboBox::drop-down			            "
             "{subcontrol-origin:padding;subcontrol-position:top right; "
             "border-radius:2px; width:20px;}"
             "QComboBox::down-arrow:on		            "
             "{border-image:url(:/widgets/image/dropdown_up/"
             "dropdown_up_normal.png);}"
             "QComboBox::down-arrow			            "
             "{border-image:url(:/widgets/image/dropdown_down/"
             "dropdown_down_normal.png);}"
             "QComboBox QAbstractItemView	            "
             "{outline:0px;border:1px solid #%3; "
             "background-color:#%2;border-radius:0px;margin-top:2px;margin-"
             "bottom:0px;}"
             "QComboBox QAbstractItemView::item			"
             "{background-color:#%2;padding-left:4px;height:24px;}"
             "QComboBox QAbstractItemView::item:hover	{background-color:#%5;}"
             "QComboBox QAbstractItemView::item:selected	"
             "{background-origin:content;background-repeat:no-repeat;}"
             //"QComboBox QAbstractItemView::item:selected
             //{color:#%4;background-image:url(:/widgets/image/dropdown_check/dropdown_check_pressed.png);background-origin:content;background-repeat:no-repeat;background-position:right;}"
             "QCheckBox                                  {color:#%1;spacing: "
             "5px;}"
             "QCheckBox::indicator                       {width:16px; "
             "height:16px;}"
             "QCheckBox::indicator:unchecked             "
             "{image:url(:/widgets/image/check/check_normal.png);}"
             "QCheckBox::indicator:unchecked:hover       "
             "{image:url(:/widgets/image/check/check_hover.png);}"
             "QCheckBox::indicator:unchecked:pressed     "
             "{image:url(:/widgets/image/check/check_pressed.png);}"
             "QCheckBox::indicator:checked               "
             "{image:url(:/widgets/image/check_selected/"
             "check_selected_normal.png);}"
             "QCheckBox::indicator:checked:hover         "
             "{image:url(:/widgets/image/check_selected/"
             "check_selected_hover.png);}"
             "QCheckBox::indicator:checked:pressed       "
             "{image:url(:/widgets/image/check_selected/"
             "check_selected_pressed.png);}"
             "QCheckBox::indicator:indeterminate         "
             "{image:url(:/widgets/image/check_part/check_part_normal.png);}"
             "QCheckBox::indicator:indeterminate:hover   "
             "{image:url(:/widgets/image/check_part/check_part_hover.png);}"
             "QCheckBox::indicator:indeterminate:pressed "
             "{image:url(:/widgets/image/check_part/check_part_pressed.png);}")
      .arg(StyleMgr::instance().color("Highlight").rgb(), 0, 16)
      .arg(StyleMgr::instance().color("BackNormal").rgb(), 0, 16)
      .arg(StyleMgr::instance().color("BorderNormal").rgb(), 0, 16)
      .arg(StyleMgr::instance().color("Highlight").rgb(), 0, 16)
      .arg(StyleMgr::instance().color("Hover").rgb(), 0, 16);
  //.arg(ImgMgr::instance().imagePath("widgets_check", WidgetStatus::kNormal))
  //.arg(ImgMgr::instance().imagePath("widgets_check", WidgetStatus::kHover))
  //.arg(ImgMgr::instance().imagePath("widgets_check", WidgetStatus::kPressed))
  //.arg(ImgMgr::instance().imagePath("widgets_check_selected",
  //WidgetStatus::kNormal))
  //.arg(ImgMgr::instance().imagePath("widgets_check_selected",
  //WidgetStatus::kHover))
  //.arg(ImgMgr::instance().imagePath("widgets_check_selected",
  //WidgetStatus::kPressed))
  //.arg(ImgMgr::instance().imagePath("widgets_check_part",
  //WidgetStatus::kNormal))
  //.arg(ImgMgr::instance().imagePath("widgets_check_part",
  //WidgetStatus::kHover))
  //.arg(ImgMgr::instance().imagePath("widgets_check_part",
  //WidgetStatus::kPressed));
}

void SCheckComboBox::hidePopup() {
  int width = this->width();
  int height = m_listWidget->height();
  int x = QCursor::pos().x() - mapToGlobal(geometry().topLeft()).x() +
          geometry().x();
  int y = QCursor::pos().y() - mapToGlobal(geometry().topLeft()).y() +
          geometry().y();
  if (x >= 0 && x <= width && y >= this->height() &&
      y <= height + this->height()) {
    // Item was clicked, do not hide popup
  } else {
    QComboBox::hidePopup();
  }
}

void SCheckComboBox::onCheckBoxClicked(bool checked) {
  QCheckBox* cb = qobject_cast<QCheckBox*>(QObject::sender());
  if (cb) {
    clickCheckBox(cb, checked);
  }
}

void SCheckComboBox::itemClicked(int index) {
  QCheckBox* cb = getCheckBox(index);
  if (cb) {
    cb->setChecked(!cb->isChecked());
    clickCheckBox(cb, cb->isChecked());
  }
}

void SCheckComboBox::clickCheckBox(QCheckBox* cb, bool checked) {
  int count = m_listWidget->count();
  if (m_hasCheckAll) {
    if (cb == m_checkBoxAll) {  // 全选
      m_checkBoxAll->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
      for (int i = 1; i < count; i++) {
        cb = getCheckBox(i);
        cb->setChecked(checked);
      }
    } else {  // 未全选
      m_checkBoxAll->setCheckState([&]() -> Qt::CheckState {
        int checked = 0;
        int unchecked = 0;
        for (int i = 1; i < count; i++) {
          cb = getCheckBox(i);
          cb->isChecked() ? checked++ : unchecked++;
        }
        if (checked == count - 1)
          return Qt::Checked;
        else if (unchecked == count - 1)
          return Qt::Unchecked;
        else
          return Qt::PartiallyChecked;
      }());
    }
  }

  int begin = m_hasCheckAll ? 1 : 0;
  QString text("");
  for (int i = begin; i < count; i++) {
    cb = getCheckBox(i);
    if (cb->isChecked()) {
      text.append(cb->text()).append("、");
    }
  }
  if (text.endsWith("、")) {
    text.remove(text.count() - 1, 1);
  }
  if (!text.isEmpty()) {
    m_lineEdit->setText(text);
  } else {
    m_lineEdit->clear();
  }
  m_lineEdit->setToolTip(text);
}

void SCheckComboBox::stateChanged(int state) {
  Q_UNUSED(state);
  emit selectionChanged();
}

void SCheckComboBox::addItem(const QString& text, const QVariant& userData) {
  Q_UNUSED(userData);
  QListWidgetItem* listWidgetItem = new QListWidgetItem(m_listWidget);
  QCheckBox* checkBox = new QCheckBox(this);
  checkBox->setText(text);
  // checkBox->setUserData(0, userData);
  m_listWidget->addItem(listWidgetItem);
  m_listWidget->setItemWidget(listWidgetItem, checkBox);
  m_comboxData.push_back(text);
  connect(checkBox, &QCheckBox::clicked, this,
          &SCheckComboBox::onCheckBoxClicked);
  connect(checkBox, &QCheckBox::stateChanged, this,
          &SCheckComboBox::stateChanged);
}

QStringList SCheckComboBox::currentText() const {
  QStringList emptyStringList;
  if (!m_lineEdit->text().isEmpty()) {
    emptyStringList = m_lineEdit->text().split(L'、');
  }
  return emptyStringList;
}

int SCheckComboBox::count() const { return m_listWidget->count(); }

void SCheckComboBox::SetPlaceHolderText(const QString& placeHolderText) {
  m_lineEdit->setPlaceholderText(placeHolderText);
}

bool SCheckComboBox::eventFilter(QObject* object, QEvent* event) {
  if (object == m_lineEdit && event->type() == QEvent::MouseButtonRelease) {
    showPopup();
    return true;
  }
  return false;
}

void SCheckComboBox::ResetSelection() {
  for (int i = 0; i < m_listWidget->count(); i++) {
    QCheckBox* cb = getCheckBox(i);
    if (cb) {
      cb->setChecked(false);
    }
  }
}

void SCheckComboBox::setCheck(int index, bool checked) {
  QCheckBox* cb = getCheckBox(index);
  if (cb) {
    if (cb != m_checkBoxAll) {
      cb->setChecked(checked);
    }
    cb->clicked(checked);
  }
}

void SCheckComboBox::setSelectStated(int index, bool selected) {
  QCheckBox* cb = getCheckBox(index);
  if (cb) {
    cb->setCheckState(selected == true ? Qt::Checked : Qt::Unchecked);
  }
}

bool SCheckComboBox::getCheck(int index) const {
  QCheckBox* cb = getCheckBox(index);
  if (cb) {
    return cb->isChecked();
  }
  return false;
}

QString SCheckComboBox::getDataText(int index) {
  if (m_comboxData.empty() || index < 0 || index > (int)m_comboxData.size()) {
    return "";
  }
  QString stData = m_comboxData.at(index);
  return stData;
}

QCheckBox* SCheckComboBox::getCheckBox(int index) const {
  QWidget* widget = m_listWidget->itemWidget(m_listWidget->item(index));
  return static_cast<QCheckBox*>(widget);
}
